//基于信号量实现的一个能体现生产者消费者模型的环形队列(数组模拟实现)
//生产者和消费者不可能同时访问同一位置
#pragma once
#include<iostream>
#include<vector>
#include<semaphore.h>
#include"Sem.hpp"
#include"Mutex.hpp"
namespace RingBufferModule
{
    using namespace SemModule;
    using namespace MutexModule;

    template<typename T>
    class RingBuffer
    {
    // private:
    //     bool IsEmpty()
    //     {
            
    //     }
    public:
        RingBuffer(int cap)
        :_ring(cap)
        ,_cap(cap)
        ,_p_step(0)
        ,_c_step(0)
        ,_datasem(0)
        ,_spacesem(cap)
        {}

        void Equeue(const T &in)
        {
            //生产者
            _spacesem.P();//等有空间
            {//临界区
                LockGuard lockguard(_p_lock);//多线程加锁，先申请信号量在申请锁更加高效（与先买电影票再排队相似）
                _ring[_p_step] = in;
                _p_step++;
                _p_step %= _cap;//维持环形特性表
            }
            _datasem.V();
        }

        void Pop(T *out)
        {
            //消费者(有数据才消费)
            _datasem.P();//等有数据
            {
                LockGuard lockguard(_c_lock);//多线程加锁，先申请信号量在申请锁更加高效（与先买电影票再排队相似）
                *out = _ring[_c_step];
                _c_step++;
                _c_step %= _cap;
            }
            _spacesem.V();//消费完后唤醒生产者
        }

        ~RingBuffer()
        {}

    private:
        std::vector<T> _ring;  //环
        int _cap;              //最大容量
        int _p_step;           //生产者位置（下标）
        int _c_step;           //消费者位置
        Sem _datasem;          //数据信号量（消费者）
        Sem _spacesem;         //空间信号量（生产者）
        Mutex _p_lock;         //生产者与生产者间的锁(多线程)
        Mutex _c_lock;         //消费者与消费者间的锁

    };
}